#include "armory.h"
#include "manager.h"
#include "monster.h"
#include "tile.h"

using std::string;

//ARMOR


std::map< string, Armor * ( * )() > & getArmorTypes()
{
	static std::map< std::string, Armor * ( * )() > armorTypes =
		std::map< std::string, Armor * ( * )() >();
	return armorTypes;
}

Armor::Armor( int x, int y, const string & name, char symbol )
	: Item( x, y, name, symbol )
{
	protection = 0;
	health = 40;
	type_.armor = 1;
}

Armor::Armor( const armor_t & baseArmor, int x, int y )
	: Item( x, y, baseArmor.name, baseArmor.symbol )
{
	health = 40;
	protection = baseArmor.protection;
	color = baseArmor.color;
	type_.armor = 1;
}

Armor::Armor() : Item( -1, -1, "Armor", ']' )
{
	protection = 0;
	health = 30;
	type_.armor = 1;
}

int Armor::getProtection() const
{
	if( health > 0 )
		return protection;
	else
		return 0;
}

int Armor::getHealth() const
{
	return health;
}

int Armor::protect( int force/*, int type*/ )
{
	health -= force;
	return getProtection();
}

//WEAPON

std::map< string, Weapon * ( * )() > & getWeaponTypes()
{
	static std::map< std::string, Weapon * ( * )() > weaponTypes =
		std::map< std::string, Weapon * ( * )() >();
	return weaponTypes;
}

Weapon::Weapon( int x, int y, const string & name, char ch )
	: Item( x, y, name, symbol )
{
	damage = 5;
	firearm = false;
	shotDamage = 0;
	type_.weapon = 1;
}

Weapon::Weapon( const weapon_t & baseWeapon, int x, int y )
	: Item( x, y, baseWeapon.name, baseWeapon.symbol )
{
	this->damage = baseWeapon.damage;
	this->firearm = baseWeapon.firearm;
	this->shotDamage = baseWeapon.shotDamage;
	type_.weapon = 1;
}

Weapon::Weapon() : Item( -1, -1, "Weapon", ')' )
{
	damage = 1;
	firearm = false;
	shotDamage = 1;
	type_.weapon = 1;
}

Weapon & Weapon::operator = ( const weapon_t & baseWeapon )
{
	this->damage = baseWeapon.damage;
	this->firearm = baseWeapon.firearm;
	this->shotDamage = baseWeapon.shotDamage;
}

int Weapon::getDamage() const
{
	return damage;
}

MapObject * Weapon::fire( MapObject * target )
{
	if( !firearm )
		return nullptr;
	int distance = 0;
	int x0, y0, x1, y1;
	x0 = owner_ ? owner_->getX() : this->x;
	y0 = owner_ ? owner_->getY() : this->y;
	x1 = target->getX();
	y1 = target->getY();
	int dX = x1 - x0;
	int dY = y1 - y0;
	if( dX < 0 )
		dX = -dX;
	if( dY < 0 )
		dY = -dY;
	int sX = 1;
	int sY = 1;
	if( x0 > x1 )
		sX = -1;
	if( y0 > y1 )
		sY = -1;
	int err = dX - dY;
	while( 1 )
	{
		Tile * t = tileAt( x0, y0 );
		if( !t->passable && distance )
		{
			t->hitEffect( shotDamage );
			return t;
		}
		Monster * m = getLiveMonster( t );
		if( m && distance )
		{
			m->hitEffect( shotDamage );
			return m;
		}
		++distance;
		if( x0 == x1 && y0 == y1 )
			break;
		int e2 = err * 2;
		if( e2 > - dY )
		{
			err -= dY;
			x0 += sX;
		}
		if( e2 < dX )
		{
			err += dX;
			y0 += sY;
		}
	}
	target->hitEffect( shotDamage );
	return target;
}

bool Weapon::isFirearm() const
{
	if( firearm )
		return true;
	return false;
}

int Weapon::hit( Monster * mon )
{
	if( !mon )
		return -1; // error
	mon->harm( damage );
	return 0;
}

LifeStealer::LifeStealer() : Weapon( -1, -1, "Weapon", ')' )
{
	damage = 5;
	uses = 7;
}

int LifeStealer::hit( Monster * mon )
{
	if( !mon )
		return -1;
	int dam = damage - mon->getProtection();
	if( dam )
	{
		mon->harm( dam );
		if( owner_ && uses )
			owner_->heal( damage / 3 ), uses--;
	}
	return 0;
}